package com.bestattempt.utility.bind.initializers.defaultImpl;

import org.apache.commons.lang.StringUtils;
import org.hibernate.collection.PersistentList;

import java.lang.reflect.Field;
import java.lang.reflect.Type;
import java.lang.reflect.ParameterizedType;
import java.util.ArrayList;
import java.util.List;

import static com.bestattempt.utility.reflection.ReflectionUtil.*;
import com.bestattempt.utility.bind.InitializerException;
import com.bestattempt.utility.bind.initializers.defaultImpl.ObjectInitializer;

/**
 * TODO: Document me
 *
 * @author Ganeshji Marwaha
 * @since Oct 14, 2006
 */
public class ListInitializer extends ObjectInitializer {

    public Object initialize(Object object, Field field, String indexStr) {
        List list = (List) getFieldValue(object, field);
        Class listClass = field.getType();

        // If the listClass is an interface, ArrayList is used by default, otherwise, the listClass is used
        if(list == null)  {
            list = listClass.isInterface() ? newInstance(ArrayList.class) : (List) newInstance(listClass);
        }

        return initList(list, indexStr, object, field);
    }

    private Object initList(List list, String indexStr, Object object, Field field) {
        // If the index is not numeric, then it is programming error. throw a RuntimeException.
        if( !StringUtils.isNumeric(indexStr) ) {
            throw new InitializerException("Non numeric index is not acceptable in List type fields");
        }

        // If the list already contains the given index, then just return it, no need to initialize it.
        int index = Integer.parseInt(indexStr);
        if(list.size() > index) {
            return list.get(index);
        }

        // If the List's generic type is not a parameterized type, then there wont be enough information to initialize.
        Type type = field.getGenericType();
        if( !(type instanceof ParameterizedType) ) {
            throw new InitializerException("Not enough type information");
        }

        Type[] types = ((ParameterizedType)type).getActualTypeArguments();

        // Since it is a List, we know that it can have only one parameter in its type. Just get that type info
        Class listGenericType = (Class) types[0];
        Object listObject = newInstance(listGenericType);
        list.add(index, listObject);

        setFieldValue(object, field, list);

        return listObject;
    }

}
